#!/usr/bin/env python

#   This script is a command line tool to schedule recordings of Audio Hijack (Pro).
#   Copyright (C) 2008 Daniel Bachmann

#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.

#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.

#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.

from appscript import *
import datetime

import getopt
import sys

class _Getch:
    # Gets a single character from standard input.  
    # Does not echo to the screen.
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

    def __call__(self): return self.impl()

def formatTD(td):
  hours = td.seconds // 3600
  minutes = (td.seconds % 3600) // 60
  if td.days>0:
    return '%s days %s hours' % (td.days, hours)
  elif hours>0:
    return '%s hours %s minutes' % (hours, minutes)
  elif  minutes>0:
    return '%s minutes' % (minutes) 
  else:
    return '%s seconds' % (td.seconds)

class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch


class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        return msvcrt.getch()


# Make a 7-character string with the days that the timer runs.
def timerdays(t):
  daylist = ['-'] * 7
  if t.runs_Monday():
    daylist[0] = 'M'
  if t.runs_Tuesday():
    daylist[1] = 'T'
  if t.runs_Wednesday():
    daylist[2] = 'W'
  if t.runs_Thursday():
    daylist[3] = 'T'
  if t.runs_Friday():
    daylist[4] = 'F'
  if t.runs_Saturday():
    daylist[5] = 'S'
  if t.runs_Sunday():
    daylist[6] = 'S'
  return "".join(daylist)


def overlap(begin, duration):
  overlap=0
  session=0
  end = begin + datetime.timedelta(seconds = duration)
  allsessions = app('Audio Hijack Pro').sessions.get()
  for s in allsessions:
    for t in s.timers.get():
      timerend=t.start_time()+datetime.timedelta(seconds = t.duration())
      if t.start_time() <= begin <= timerend or t.start_time() <= end <= timerend:
        return t,s.name()
      if begin <= t.start_time() and timerend <= end:
        return t,s.name()
  return overlap,session

def remove_timer(session):
    if session: 
      for t in session.timers.get():
        show_timer(t,session.name())
        print "remove this timer? y/n"
        input = _Getch()
        for i in xrange(sys.maxint):
          c = input()
          if c <> '':break
        if c=="y":
          t.delete()
          print "deleted"
    else:
      print "no session selected"  

def add_timer(session):
    if session:
      print "add timer to session", session.name(), "? y/n"
      input = _Getch()
      for i in xrange(sys.maxint):
        c = input()
        if c <> '':break
      if c=="y":
        print "enter new begin (YYYY-MM-DD hh:mm:ss):"
        begin = sys.stdin.readline() 
        begin = begin.strip()
        date=datetime.datetime.strptime(begin,"%Y-%m-%d %H:%M:%S")
        print "enter duration in minutes:"
        minutes = sys.stdin.readline() 
        minutes = minutes.strip()
        duration = int(minutes) * 60
        overlap_timer, sname =overlap(date, duration)
        if overlap_timer: 
          print "WARNING: overlap detected with another timer:"
          show_timer(overlap_timer, sname)
          print "do you really want to create this timer? y/n"
          input = _Getch()
          for i in xrange(sys.maxint):
            c = input()
            if c <> '':break
          if c=="y":
            timer = session.make(new=k.timer)
            timer.actions.set(['record','mute'])
            timer.start_time.set(date)
            timer.duration.set(duration)
            print "timer created"
            show_timer(timer,session.name())
        else:
          timer = session.make(new=k.timer)
          timer.actions.set(['record','mute'])
          timer.start_time.set(date)
          timer.duration.set(duration)
          timer.enabled.set(True)
          print "timer created"
          show_timer(timer,session.name())
    else:
      print "no session selected"  

def change_timer(session):
    if session:
      for t in session.timers.get():
        show_timer(t,session.name())
        c=""
        while c != "n":
          print "(a)bort (n)ext (i)nfo | Timer (b)egin (d)uration a(ctions) (s)chedule | switch (e)nabled" 
          input = _Getch()
          for i in xrange(sys.maxint):
            c = input()
            if c <> '':break
          if c=="a":
            print "change aborted"
            return 
          elif c=="b":
            print "old begin:", t.start_time()
            print "change status? y/n"
            input = _Getch()
            for i in xrange(sys.maxint):
              ch = input()
              if ch <> '':break
            if ch=="y":
              print "enter new begin (YYYY-MM-DD hh:mm:ss):"
              begin = sys.stdin.readline() 
              begin = begin.strip()
              date=datetime.datetime.strptime(begin,"%Y-%m-%d %H:%M:%S")
              overlap_timer, sname =overlap(date, t.duration())
              if overlap_timer: 
                print "WARNING: overlap detected with another timer:"
                show_timer(overlap_timer, sname)
                print "do you really want to create this timer? y/n"
                input = _Getch()
                for i in xrange(sys.maxint):
                  c = input()
                  if c <> '':break
                if c=="y":
                  t.start_time.set(date)
                  t.enabled.set(False)
                  print "new begin:",t.start_time()
              else:
                t.start_time.set(date)
                print "new begin:",t.start_time()
                
          elif c=="a":
            #allactions=['record','mute','quit']
            allactions=['record','mute']             # quit doesn't work stable, so removed it from actions
            actions=t.actions()
            for action in actions:
              print "action:",action
            if len(actions)>0:
              for action in actions:
                print "remove action", action,"? y/n"
                input = _Getch()
                for i in xrange(sys.maxint):
                  ch = input()
                  if ch <> '':break
                if ch=="y":
                  actions.remove(action)
                  t.actions.set(actions)
                  actions=t.actions()
                  print action, "removed"
            for action in allactions:
              if action not in actions:
                print "add action", action,"? y/n"
                input = _Getch()
                for i in xrange(sys.maxint):
                  ch = input()
                  if ch <> '':break
                if ch=="y":
                  actions.append(action) 
                  t.actions.set(actions)
                  print "action", action, "added"
          elif c=="i":
            timer_info(t)
            show_timer(t,session.name())
          elif c=="d":
            print "old duration:", t.duration(),"(s)"
            print "change status? y/n"
            input = _Getch()
            for i in xrange(sys.maxint):
              ch = input()
              if ch <> '':break
            if ch=="y":
              print "enter duration in minutes:"
              minutes = sys.stdin.readline() 
              minutes = minutes.strip()
              duration = int(minutes) * 60
              overlap_timer, sname =overlap(date, t.duration())
              if overlap_timer: 
                print "WARNING: overlap detected with another timer:"
                show_timer(overlap_timer, sname)
                print "do you really want to create this timer? y/n"
                input = _Getch()
                for i in xrange(sys.maxint):
                  c = input()
                  if c <> '':break
                if c=="y":
                  t.duration.set(duration)
                  t.enabled.set(False)
                  print "new duration:",t.duration(),"(s)"
              else:
                t.duration.set(duration)
                print "new duration:",t.duration(),"(s)"
          elif c=="e":
            print "enable:",t.enabled()
            print "change status? y/n"
            input = _Getch()
            for i in xrange(sys.maxint):
              ch = input()
              if ch <> '':break
            if ch=="y":
              t.enabled.set(not t.enabled()) 
              print "enable:",t.enabled()
          elif c=="s":
            print "timerdays:",timerdays(t)
            print "change timerdays? y/n"
            input = _Getch()
            for i in xrange(sys.maxint):
              ch = input()
              if ch <> '':break
            if ch=="y":
              ch=""
              while ch != "d":
                fmtstr = "(d)one | switch %s (0-6) starting with (0) monday"
                print fmtstr % (timerdays(t))
                input = _Getch()
                for i in xrange(sys.maxint):
                  ch = input()
                  if ch <> '':break
                if ch=="0":
                  t.runs_Monday.set(not t.runs_Monday())
                if ch=="1":
                  t.runs_Tuesday.set(not t.runs_Tuesday())
                if ch=="2":
                  t.runs_Wednesday.set(not t.runs_Wednesday())
                if ch=="3":
                  t.runs_Thursday.set(not t.runs_Thursday())
                if ch=="4":
                  t.runs_Friday.set(not t.runs_Friday())
                if ch=="5":
                  t.runs_Saturday.set(not t.runs_Saturday())
                if ch=="6":
                  t.runs_Sunday.set(not t.runs_Sunday())
                if ch=="d":
                  print "timerdays:",timerdays(t)
          elif c=="n":
            show_timer(t,session.name())
          else :
            print "unknown key. type s to skip changing this timer"
    else:
      print "no session selected"  

def show_timer(timer, sessionname):
    dur = timer.duration()
    durstr = '(%d min)' % (dur/60)
    st = timer.start_time()
    et = st + datetime.timedelta(seconds = dur)
    ststr = st.strftime("%c")
    etstr = et.strftime("%c")
    a=" "
    b=" "
    c=" "
    dow=""
    actions=""
    if timer.active():
      a="x"
    if timer.enabled():
      b="x"
    if timer.scheduled():
      c="x"  
      dow = timerdays(timer)
      actions=" ".join(timer.actions())
    fmtstr = "session timer <%s> (in %s) [%s]"
    in_time = timer.start_time()-datetime.datetime.now()
    print fmtstr % (sessionname,formatTD(in_time), actions)
    fmtstr = "%s - %s %s [%s] active [%s] enabled [%s] scheduled %s"
    print fmtstr % (ststr, etstr, durstr.rjust(9),a,b,c,dow)
  

def timer_info(timer):
    if timer:
      for item in timer.properties(): 
        print item,"=", timer.properties().get(item)
    else:
      print "no timer selected"

def session_info(session):
    if session:
      for item in session.properties(): 
        print item,"=", session.properties().get(item)
    else:
      print "no session selected"

def select_session():
    list_sessions()
    allsessions = app('Audio Hijack Pro').sessions.get()
    print "select session no ( 0 -" , len(allsessions),")"
    input = sys.stdin.readline() 
    input = input.strip()
    try:
      no = int(input) 
    except: 
      no = 0
    i=1
    for s in allsessions:
      if i == no:
         return s
      i=i+1
      
    return ""

def list_sessions():
    allsessions = app('Audio Hijack Pro').sessions.get()
    #print "( 0 ) < none >"
    i=0
    string="< none >"
    for s in allsessions:
      timers=s.timers.get()
      if not string:
        string=s.name()
      if i%2==0:
        print "(",i,")", string, "(",i+1,")",s.name()
        string=""
      i=i+1
    if i%2==0:
      print "(",i,")", string

def list_timers(session):
    # list timers of session
    timers = []
    found=0
    has_old=0
    now = datetime.datetime.now()
    if session:
        for t in session.timers.get():
           end=t.start_time()+datetime.timedelta(seconds = t.duration())
           if end < now and not t.scheduled(): 
              has_old=1
           show_timer(t,session.name())
           found=1
    else:
        allsessions = app('Audio Hijack Pro').sessions.get()
        for s in allsessions:
          for t in s.timers.get():
            end=t.start_time()+datetime.timedelta(seconds = t.duration())
            if end < now and not t.scheduled(): 
              has_old=1
            show_timer(t,s.name())
            found=1
    
    if not found:
      print "no timers found for session", session.name()
    if has_old:
      print "remove old timers? y/n"
      input = _Getch()
      for i in xrange(sys.maxint):
        c = input()
        if c <> '':break
      if c=="y":
        for s in allsessions:
          for t in s.timers.get():
            end=t.start_time()+datetime.timedelta(seconds = t.duration())
            if end < now and not t.scheduled(): 
              t.delete()
              print "old timer deleted"

def show_help():
  show_application_info()
  print "VIEW:"
  print "- press 'l' to list all sessions"
  print "- press 't' to list all timers of selected session"
  print "  if no session is selected, timers of all sections are listed"
  print "- press 'q' to quit"
  print "- press 's' and session number to select session"
  print "\n\nACTIONS:"
  print "\nadd timer"
  print "(1) select session"
  print "(2) press 'a' to add timer"
  print "(3) follow instructions"
  print "\nchange start time of timer"
  print "(1) select session"
  print "(2) press 'cb' and enter start time (YYYY-MM-DD hh:mm:ss)"
  print "\nchange duration of timer"
  print "(1) select session"
  print "(2) press 'cd' and enter duration (in minutes)"
  print "\nchange schedule weekdays of timer"
  print "(1) select session"
  print "(2) press 'cs' and switch weekdays with keys (0-6) starting with 0=monday, 6=sunday"
  print "\nchange actions of timer (record, mute)"
  print "(1) select session"
  print "(2) press 'ca' and follow instructions"
  print "\nactivate/deactivate timer"
  print "(1) select session"
  print "(2) press 'ce' and follow instructions"
  print "\nremove timer"
  print "(1) select session"
  print "(2) press 'cr' and follow instructions"
  print "\n\n"

def show_application_info():
    print "Audio Hijack Console v1.0"
    print "coded by Daniel Bachmann (Nov 2008)\n"

def main():
    session=""
    show_application_info()
    c = ""
    while c != "q":
      if session:
        print "Main Menu: session <", session.name(),"> selected"
      else:
        print "Main Menu: session < none >"
      print "Actions: (l)ist (t)imers (h)elp (q)uit | Session (s)elect (i)nfo | Timer (a)dd (c)hange (r)emove"
      print "> ==="
      input = _Getch()
      for i in xrange(sys.maxint):
        c = input()
        if c <> '':break
      if c=="l":
        list_sessions()
      if c=="h":
        show_help()
      elif c=="t":
        list_timers(session)
      elif c=="s":
        session=select_session()
      elif c=="i":
        session_info(session)
      elif c=="r":
        remove_timer(session)
      elif c=="c":
        change_timer(session)
      elif c=="a":
        add_timer(session)
      elif c=="q": 
        print "bye"

if __name__ == "__main__":
    main()
